#ifndef _CPP_STORY_MACROS_H_
#define _CPP_STORY_MACROS_H_

#include "helper.h"

#define JOIN(X, Y) DO_JOIN(X, Y)
#define DO_JOIN(X, Y) DO_JOIN2(X, Y)
#define DO_JOIN2(X, Y) X##Y

#define GEN_UNIQUE_NAME(prefix) \
GEN_(JOIN(prefix, __COUNTER__))

#define GEN_(unique_name) \
GEN2_(unique_name)

#define GEN2_(unique_name) \
    unique_name

#define FEATURE(name) \
    class Feature##name : public Feature \
    { \
    public: \
        Feature##name(const char* f, const int l) \
        : Feature(f, l) \
        { \
            set_feature_name(#name); \
        } \
    }; \
    static FeatureRegisterHelper GEN_UNIQUE_NAME(feature_register_helper)(new Feature##name(__FILE__, __LINE__));

#define IN_ORDER(i) \
    static InOrderHelper GEN_UNIQUE_NAME(in_order_helper)(i);

#define AS(w) \
    static AsHelper GEN_UNIQUE_NAME(as_helper)(w);

#define I_WANT(w) \
    static IWantHelper GEN_UNIQUE_NAME(i_want_helper)(w);

#define SCENARIO(name) \
    static ScenarioRegisterHelper GEN_UNIQUE_NAME(scenario_register_helper)(new Scenario(__FILE__, __LINE__)); \
    static ScenarioNameHelper GEN_UNIQUE_NAME(scenario_name_helper)(name);

#define GIVEN(given) \
    static StepRegisterHelper GEN_UNIQUE_NAME(step_register_helper)(new Given(__FILE__, __LINE__)); \
    static StepNameHelper GEN_UNIQUE_NAME(step_name_helper)(given);

#define AND(a) \
    static StepRegisterHelper GEN_UNIQUE_NAME(step_register_helper)(new And(__FILE__, __LINE__)); \
    static StepNameHelper GEN_UNIQUE_NAME(step_name_helper)(a);

#define WHEN(when) \
    static StepRegisterHelper GEN_UNIQUE_NAME(step_register_helper)(new When(__FILE__, __LINE__)); \
    static StepNameHelper GEN_UNIQUE_NAME(step_name_helper)(when);

#define THEN(then) \
    static StepRegisterHelper GEN_UNIQUE_NAME(step_register_helper)(new Then(__FILE__, __LINE__)); \
    static StepNameHelper GEN_UNIQUE_NAME(step_name_helper)(then);

#define BUT(but) \
    static StepRegisterHelper GEN_UNIQUE_NAME(step_register_helper)(new But(__FILE__, __LINE__)); \
    static StepNameHelper GEN_UNIQUE_NAME(step_name_helper)(but);

#define STEP_DEF(regex_str) \
STEP_DEF2(GEN_UNIQUE_NAME(StepDefinition), GEN_UNIQUE_NAME(StepDefinitionImpl), regex_str)

#define STEP_DEF2(class_name, object_name, regex_str) \
    class JOIN(STEP_MODULE, class_name) : public StepDefinition \
    { \
    public: \
        JOIN(STEP_MODULE, class_name)(std::string str) : StepDefinition(str, __FILE__, __LINE__) { } \
        bool run_impl(); \
    }; \
    static StepDefinitionRegisterHelper GEN_UNIQUE_NAME(step_def_register_helper)(new JOIN(STEP_MODULE, class_name)(#regex_str)); \
    bool JOIN(STEP_MODULE, class_name)::run_impl()

#define REGEX_INT(name) const int name(FromString<int>(get_next_group()))
#define REGEX_DOUBLE(name) const double name(FromString<double>(get_next_group()))
#define REGEX_STRING(name) const std::string name(get_next_group())

#define CONTEXT(type, name) ContextPtrImpl<type> name(this)

#define TABLE(str) \
    static TableCreateHelper GEN_UNIQUE_NAME(table_create_helper); \
    static TableStrHelper GEN_UNIQUE_NAME(table_str_helper)(str);

#define EXAMPLES(str) \
    static ExamplesCreateHelper GEN_UNIQUE_NAME(samples_create_helper); \
    static ExamplesTableStrHelper GEN_UNIQUE_NAME(samples_table_str_helper)(str);

#define BACKGROUND() \
    static BackgroundCreateHelper GEN_UNIQUE_NAME(background_create_helper);

#define CHECK_EQUAL(expected, actual) \
    do \
    { \
        if (!((expected) == (actual))) \
        { \
            set_failed_file(__FILE__); \
            set_failed_line(__LINE__); \
            std::stringstream msg; \
            msg << "expected: '" << (expected) << "' but was: '" << (actual) << "'"; \
            set_failed_message(msg.str().c_str()); \
            return false; \
        } \
    } \
    while (0);

#define USING_TABLE(name) Table* name = get_table()

#endif

